﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.BizTalk.Bam.EventObservation;
using Microsoft.Practices.ESB.Exception.Management;
using System.Reflection;

namespace ESB.BAM.Wrappers
{
    /// <summary>
    /// This class encapsulates the BAM API calls
    /// </summary>
    public abstract class BAMAPIWrapper
    {
        #region Static Fields
        static string BAMReferencePageUrl = GetBAMReferencePageUrl();

        /// <summary>
        /// Gets the BAM reference page URL from the ESB.Config file.
        /// </summary>
        /// <returns></returns>
        private static string GetBAMReferencePageUrl()
        {
            var callToken = Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceIn();
            string url = "";
            try
            {
                url = Microsoft.Practices.ESB.Configuration.ConfigHelper.ESBConfig.ExtendedConfig["ReferenceViewPageUrl"].Value;
            }
            catch (Exception ex)
            {
                Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceError(ex, true, callToken);
                EventLogger.LogMessage(EventFormatter.FormatEvent(MethodBase.GetCurrentMethod(), ex), System.Diagnostics.EventLogEntryType.Error, 0x17cb);
            }
            Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceOut(callToken, url);
            return url;
        }
        static System.Configuration.ConnectionStringSettings ConString = Microsoft.Practices.ESB.Configuration.ConfigHelper.GetConnectionSettings("ESB.BAM.DAL.Properties.Settings.BAMConnectionString");
        static bool bIsUseDirectStream = GetIsUseDirectStream();

        /// <summary>
        /// Gets the boolean to use direct stream from the ESB.Config file.
        /// </summary>
        /// <returns></returns>
        private static bool GetIsUseDirectStream()
        {
            var callToken = Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceIn();
            bool _bIsUseDirect = true;
            try
            {
                _bIsUseDirect = bool.Parse(Microsoft.Practices.ESB.Configuration.ConfigHelper.ESBConfig.ExtendedConfig["IsUseDirectStreamForOrchestrations"].Value);
            }
            catch (Exception ex)
            {
                Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceError(ex, true, callToken);
                EventLogger.LogMessage(EventFormatter.FormatEvent(MethodBase.GetCurrentMethod(), ex), System.Diagnostics.EventLogEntryType.Warning, 0x17cb);
            }
            Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceOut(callToken, _bIsUseDirect);
            return _bIsUseDirect;
        }

        static DirectEventStream _BamDirStream = null;
        /// <summary>
        /// Gets the bam event direct stream.
        /// Also initializes this object if it is not initialized
        /// Thread safe
        /// </summary>
        static DirectEventStream BamDirStream
        {
            get
            {
                var callToken = Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceIn();
                try
                {
                    if (_BamDirStream == null)
                    {
                        lock (typeof(BAMAPIWrapper))
                        {
                            if (_BamDirStream == null)
                            {
                                _BamDirStream = new DirectEventStream(ConString.ToString(), 0);
                            }
                        }
                    }
                    Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceOut(callToken, _BamDirStream);
                    return _BamDirStream;
                }
                catch (Exception ex)
                {
                    Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceError(ex, true, callToken);
                    EventLogger.LogMessage(EventFormatter.FormatEvent(MethodBase.GetCurrentMethod(), ex), System.Diagnostics.EventLogEntryType.Error, 0x17cb);
                    Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceOut(callToken);
                    return null;
                }
            }
        }
        #endregion

        #region BAM Wrappers

        /// <summary>
        /// Updates the activity reference.
        /// </summary>
        /// <param name="BAMStream">The BAM stream.</param>
        /// <param name="ActivityName">Name of the activity.</param>
        /// <param name="id">The id.</param>
        /// <param name="ReferenceName">Name of the reference.</param>
        /// <param name="strMsgBody">The STR MSG body.</param>
        public static void UpdateActivityReference(EventStream BAMStream, string ActivityName, string id, string ReferenceName, string strMsgBody)
        {
            var callToken = Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceIn(BAMStream, ActivityName, id, ReferenceName, strMsgBody);
            // TODO: Add message body compression here
            string RefUrl = BAMReferencePageUrl + "?id=" + id + "&name=" + ReferenceName;
            if (BAMStream == null)
            {
                if (!bIsUseDirectStream || BamDirStream == null)
                {
                    // Orchestration stream
                    OrchestrationEventStream.AddReference(ActivityName, id, "DocumentUrl", ReferenceName, RefUrl, strMsgBody);
                }
                else
                {
                    BamDirStream.AddReference(ActivityName, id, "DocumentUrl", ReferenceName, RefUrl, strMsgBody);
                    BamDirStream.Flush();
                }
            }
            else
            {
                BAMStream.AddReference(ActivityName, id, "DocumentUrl", ReferenceName, RefUrl, strMsgBody);
                BAMStream.Flush();
            }
            Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceOut(callToken);
        }

        /// <summary>
        /// Updates the activity data.
        /// </summary>
        /// <param name="BAMStream">The BAM stream.</param>
        /// <param name="ActivityName">Name of the activity.</param>
        /// <param name="id">The id.</param>
        /// <param name="DataName">Name of the data.</param>
        /// <param name="DataValue">The data value.</param>
        public static void UpdateActivityData(EventStream BAMStream, string ActivityName, string id, string DataName, string DataValue)
        {
            var callToken = Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceIn(BAMStream, ActivityName, id, DataName, DataValue);
            if (BAMStream == null)
            {
                if (!bIsUseDirectStream || BamDirStream == null)
                {
                    // Orchestration stream
                    OrchestrationEventStream.UpdateActivity(ActivityName, id, DataName, DataValue);
                }
                else
                {
                    BamDirStream.UpdateActivity(ActivityName, id, DataName, DataValue);
                    BamDirStream.Flush();
                }
            }
            else
            {
                BAMStream.UpdateActivity(ActivityName, id, DataName, DataValue);
                BAMStream.Flush();
            }
            Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceOut(callToken);
        }

        /// <summary>
        /// Updates the activity.
        /// </summary>
        /// <param name="BAMStream">The BAM stream.</param>
        /// <param name="ActivityName">Name of the activity.</param>
        /// <param name="id">The id of the activity.</param>
        /// <param name="MilestoneName">Name of the milestone.</param>
        /// <param name="TimeStamp">The time stamp.</param>
        public static void UpdateActivity(EventStream BAMStream, string ActivityName, string id, string MilestoneName, DateTime TimeStamp)
        {
            var callToken = Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceIn(BAMStream, ActivityName, id, MilestoneName, TimeStamp);
            if (!string.IsNullOrEmpty(MilestoneName) && MilestoneName != "_")
            {
                if (BAMStream == null)
                {
                    if (!bIsUseDirectStream || BamDirStream == null)
                    {
                        // Orchestration stream
                        OrchestrationEventStream.UpdateActivity(ActivityName, id, MilestoneName, TimeStamp);
                    }
                    else
                    {
                        BamDirStream.UpdateActivity(ActivityName, id, MilestoneName, TimeStamp);
                        BamDirStream.Flush();
                    }
                }
                else
                {
                    BAMStream.UpdateActivity(ActivityName, id, MilestoneName, TimeStamp);
                    BAMStream.Flush();
                }
            }
            Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceOut(callToken);
        }

        /// <summary>
        /// Starts the activity.
        /// </summary>
        /// <param name="BAMStream">The BAM stream.</param>
        /// <param name="ActivityName">Name of the activity.</param>
        /// <param name="id">The id of the activity.</param>
        public static void StartActivity(EventStream BAMStream, string ActivityName, string id)
        {
            var callToken = Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceIn(BAMStream, ActivityName, id);
            if (BAMStream == null)
            {
                if (!bIsUseDirectStream || BamDirStream == null)
                {
                    // Orchestration stream
                    OrchestrationEventStream.BeginActivity(ActivityName, id);
                }
                else
                {
                    BamDirStream.BeginActivity(ActivityName, id);
                    BamDirStream.Flush();
                }
            }
            else
            {
                BAMStream.BeginActivity(ActivityName, id);
                BAMStream.Flush();
            }
            Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceOut(callToken);
        }

        /// <summary>
        /// Ends the activity.
        /// </summary>
        /// <param name="BAMStream">The BAM stream.</param>
        /// <param name="ActivityName">Name of the activity.</param>
        /// <param name="id">The id.</param>
        public static void EndActivity(EventStream BAMStream, string ActivityName, string id)
        {
            var callToken = Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceIn(BAMStream, ActivityName, id);
            if (BAMStream == null)
            {
                if (!bIsUseDirectStream || BamDirStream == null)
                {
                    // Orchestration stream
                    OrchestrationEventStream.EndActivity(ActivityName, id);
                }
                else
                {
                    BamDirStream.EndActivity(ActivityName, id);
                    BamDirStream.Flush();
                }
            }
            else
            {
                BAMStream.EndActivity(ActivityName, id);
                BAMStream.Flush();
            }
            Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceOut(callToken);
        }

        /// <summary>
        /// Enables the continuation on the specific activity.
        /// </summary>
        /// <param name="BAMStream">The BAM stream.</param>
        /// <param name="ActivityName">Name of the activity.</param>
        /// <param name="OldId">The old activity id.</param>
        /// <param name="NewId">The new activity id.</param>
        public static void EnableContinuation(EventStream BAMStream, string ActivityName, string OldId, string NewId)
        {
            var callToken = Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceIn(BAMStream, ActivityName, OldId, NewId);
            if (BAMStream == null)
            {
                if (!bIsUseDirectStream || BamDirStream == null)
                {
                    // Orchestration stream
                    OrchestrationEventStream.EnableContinuation(ActivityName, OldId, NewId);
                }
                else
                {
                    BamDirStream.EnableContinuation(ActivityName, OldId, NewId);
                    BamDirStream.Flush();
                }
            }
            else
            {
                BAMStream.EnableContinuation(ActivityName, OldId, NewId);
                BAMStream.Flush();
            }
            Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.TrackingComponent.TraceOut(callToken);
        }

        #endregion
    }
}
